/* * 作者:蘇文宏 * 學號:8324057 * 本程式,建議使用 jdk 1.0x 編譯執行 * 如使用 jdk 1.1.x 版編譯,則會有『1 warning』出現, * 放心這是正常現象 */ import java.applet.*; import java.awt.*; import java.util.*; // 框架視窗類別,就是有最大化、最小化…的框框 final class MyFrame2 extends Frame{ static int frameNumber=0;// 計錄總數 static int frameIndex=0;// 框架索引 public MyFrame2(String str){ super(str+" - "+ ++frameIndex);// 標題是第 frameIndex 個框架視窗 frameNumber++; } public boolean handleEvent(Event evt){ if(evt.id==Event.WINDOW_DESTROY){// 如果按下了『視窗關閉』 if(--frameNumber==0){// 如果全部都結束了 dispose(); System.exit(0);// 離開 java 虛擬機器 } else dispose();// 關閉框架視窗 } return super.handleEvent(evt);// 丟給父類別處理 } }//end of class MyFrame2 // 放 awt 元件的容器 final class MyPanel2 extends Panel{ final static int TEXT_STRING_LENGTH=30;// 輸入算式最大字元數 final static int TEXT_FIELD_NUMBER=3;// 一個輸出後序,一個輸出數值,一個輸入 final static int POSTFIX=0;// 定義常數,代表後序運算式 public final static int ANSWER=1;// 定義常數,代表輸出 public final static int INPUT=2;// 定義常數,代表輸入 final static int DEGREE=0;// 定義常數,代表度數 final static int RADIAN=1;// 定義常數,代表弳度量 final static String AC="Ac";// 定義『清除鍵』 final static String EXEC="Exec";// 定義『執行鍵』 Evaluate ev; String[] pad; Panel panelSmall; Panel panelBig; Label[] label; Button btnPad[]; TextField[] textField; TextField x; Checkbox[] chkBox; Button newWindowBtn; // 初使化,按鍵、文字區、標題……等 public MyPanel2(){ int i;// 迴圈專用變數 Font font=new Font("",Font.PLAIN,16); setBackground(Color.lightGray); setFont(font); // 設定鍵盤 i=0; ev=new Evaluate(); String SPACE=" "; String[] pad={// 鍵盤按鍵 ev.functionTable[i++].name+SPACE,ev.functionTable[i++].name+SPACE,ev.functionTable[i++].name+SPACE,ev.functionTable[i++].name+SPACE, ev.functionTable[i++].name+SPACE,ev.functionTable[i++].name+SPACE,ev.functionTable[i++].name+SPACE,ev.functionTable[i++].name+SPACE, ev.functionTable[i++].name+SPACE," ^2 ",SPACE+ev.functionTable[i++].name+SPACE,ev.functionTable[i++].name+SPACE, ev.functionTable[i++].name+SPACE," ^-1 ",ev.functionTable[i++].name+SPACE,ev.functionTable[i++].name+SPACE, "(",")",SPACE+ev.functionTable[i++].name+SPACE,AC, "7","8","9",SPACE+ev.functionTable[i++].name+SPACE, "4","5","6",SPACE+ev.functionTable[i++].name+SPACE, "1","2","3",SPACE+ev.functionTable[i++].name+SPACE, "0",".",SPACE+ev.functionTable[i++].name+SPACE,EXEC }; // 這一段,設定標題,輸出入文字欄 //postfix [ ] //answer [ ] //input [ ] textField=new TextField[TEXT_FIELD_NUMBER]; textField[POSTFIX]=new TextField(TEXT_STRING_LENGTH); textField[ANSWER]=new TextField(TEXT_STRING_LENGTH); textField[INPUT]=new TextField(TEXT_STRING_LENGTH); GridBagLayout gridBag=new GridBagLayout(); GridBagConstraints c= new GridBagConstraints(); panelSmall=new Panel(); panelSmall.setLayout(gridBag); Label lb; c.fill=GridBagConstraints.BOTH; lb=new Label("Author : Wen-Hung Su",Label.CENTER); c.gridwidth=GridBagConstraints.REMAINDER; gridBag.setConstraints(lb,c); panelSmall.add(lb); lb.setForeground(Color.blue); lb=new Label("E-mail : b8324057@student.nsysu.edu.tw",Label.CENTER); gridBag.setConstraints(lb,c); panelSmall.add(lb); lb.setForeground(Color.blue); lb=new Label("postfix"); c.weightx=1.0; c.gridwidth=1; gridBag.setConstraints(lb,c); panelSmall.add(lb); c.weightx=3.0; c.gridwidth=GridBagConstraints.REMAINDER; gridBag.setConstraints(textField[POSTFIX],c); panelSmall.add(textField[POSTFIX]); textField[POSTFIX].setEditable(false);// 設定成不可修改 lb=new Label("answer"); c.weightx=1.0; c.gridwidth=1; gridBag.setConstraints(lb,c); panelSmall.add(lb); c.weightx=3.0; c.gridwidth=GridBagConstraints.REMAINDER; gridBag.setConstraints(textField[ANSWER],c); panelSmall.add(textField[ANSWER]); textField[ANSWER].setEditable(false);// 設定成不可修改 lb=new Label("input"); c.weightx=1.0; c.gridwidth=1; gridBag.setConstraints(lb,c); panelSmall.add(lb); c.weightx=1.0; c.gridwidth=GridBagConstraints.REMAINDER; gridBag.setConstraints(textField[INPUT],c); panelSmall.add(textField[INPUT]); // 這一段,設定 x=[0 ] ○degree ☉radian chkBox=new Checkbox[2]; CheckboxGroup chkGroup=new CheckboxGroup(); chkBox[DEGREE]=new Checkbox("degree",chkGroup,false); chkBox[RADIAN]=new Checkbox("radian",chkGroup,true); c.weightx=0.3; c.gridwidth=1; lb=new Label("x="); gridBag.setConstraints(lb,c); panelSmall.add(lb); c.weightx=1.0; x=new TextField("0",10); gridBag.setConstraints(x,c); panelSmall.add(x); gridBag.setConstraints(chkBox[DEGREE],c); panelSmall.add(chkBox[DEGREE]); c.gridwidth=GridBagConstraints.REMAINDER; gridBag.setConstraints(chkBox[RADIAN],c); panelSmall.add(chkBox[RADIAN]); // 這一段,設定數字及函數按鍵 btnPad=new Button[pad.length]; panelBig=new Panel(); for(i=0;i<20;i++){ panelBig.add(btnPad[i]=new Button(pad[i])); btnPad[i].setBackground(Color.green); } for(;i<pad.length;i++){ panelBig.add(btnPad[i]=new Button(pad[i])); btnPad[i].setBackground(Color.yellow); } // 這一段,把上面的文字欄、標題、按鍵…加入我的『容器』 panelBig.setLayout(new GridLayout(9,4,2,2)); setLayout(new BorderLayout()); add("North",panelSmall); add("Center",panelBig); newWindowBtn=new Button("New window"); add("South",newWindowBtn); }//end of MyPanel2() // 控制按鍵 public boolean action(Event evt,Object obj){ if(evt.target instanceof Button){ String btnLabel=(String)obj; if(btnLabel.equals(EXEC)){// 按了『執行鍵』 go(); return true; } else if(btnLabel.equals(AC)){// 按了『清除鍵』 for(int i=0;i<TEXT_FIELD_NUMBER;i++) clearTextString(i); return true; }else if(evt.target==newWindowBtn){// 按了『新視窗鍵』 MyFrame2 frame=new MyFrame2("[ Home Work 2 ]"); frame.setLayout(new BorderLayout(0,0)); frame.add("Center",new MyPanel2());// 加到中間 frame.pack();// 自動排列大小 frame.show();// 顯示 return true; }else{ textField[INPUT].setText(textField[INPUT].getText()+ btnLabel); return true; }//end if-else }//end if instanceof Button else if(evt.target instanceof TextField){ if(evt.target==textField[INPUT] || evt.target==x){ go(); return true; } } return false;// 沒有做事,則傳回 false }//end of action() public void clearTextString(int i){// 清除第 i 個文字區塊 textField[i].setText(""); } public void setTextField(int index,String str){ textField[index].setText(str); } // 真正的主程式 public void go(){ try{ double ans; String str=x.getText(); Evaluate ev1=new Evaluate(str); ans=ev1.getValue(ev.getX()); x.setText(String.valueOf(ans)); //x.setText(Double.valueOf("1 e6").doubleValue()+""); ev.setX(ans);// 重設 x ev.setDegreeState(chkBox[DEGREE].getState());// 是弳度或角度 str=textField[INPUT].getText(); ev.setExpression(str); setTextField(POSTFIX,ev.getPostfix()); ans=ev.getValue(); setTextField(ANSWER,String.valueOf(ans)); } catch(NumberFormatException e){ setTextField(ANSWER,e.toString()); } catch(NoSuchMethodError e){ setTextField(ANSWER,e.toString()); } catch(Exception e){ setTextField(ANSWER,e.toString()); } catch(Error e){ setTextField(ANSWER,e.toString()); } }//end of go() }//end of class MyPanel2 interface ComputeData{ // 需要幾個參數來計算 final static int NONE=0; final static int UNARY_OPERATOR=1; final static int BINARY_OPERATOR=2; // 計算優先次序。數值越大,則優先次序越高。 final static int LEVAL_UP=100;// 向上加一大等級 final static int LEVAL_DOWN=-LEVAL_UP;// 向下減一大等級 final static int LEVAL1=40;// 括 final static int LEVAL2=35;// 變數 x,pi final static int LEVAL3=30;// 次方,^,正負號 + - final static int LEVAL4=25;// 保留 final static int LEVAL5=20;// 一般超越函數 final static int LEVAL6=15;// *,/ final static int LEVAL7=10;// +,- final static int LEVAL8=5;// 最低等級 final static int SIN=0; final static int COS=1; final static int TAN=2; final static int ASIN=3; final static int ACOS=4; final static int ATAN=5; final static int EXP=6; final static int LN=7; final static int SQRT=8; final static int POW=9; final static int X=10; final static int PI=11; final static int ADD=12; final static int SUB=13; final static int MUL=14; final static int DIV=15; final static int LOG=16; final static int ANS=17; final static int MOD=18; final static int SIZE=19; }//end of class ComputeData class EvaluateData{ String name; int priority; int operator; int id; EvaluateData(String name,int priority,int operator,int id){ this.name=name; this.priority=priority; this.operator=operator; this.id=id; } }//end of class EvaluateData class Evaluate implements ComputeData{ private Hashtable hash; private Stack stack; private String postfix=null; private String expression="0"; private String errorMessage="No error !"; private boolean isDegree=false; private double x=0.0d; private double lastAnswer=0d; public EvaluateData[] functionTable; public Evaluate(){ int i=0; stack=new Stack(); functionTable=new EvaluateData[SIZE]; functionTable[i++]=new EvaluateData("sin",LEVAL5,UNARY_OPERATOR,SIN); functionTable[i++]=new EvaluateData("cos",LEVAL5,UNARY_OPERATOR,COS); functionTable[i++]=new EvaluateData("tan",LEVAL5,UNARY_OPERATOR,TAN); functionTable[i++]=new EvaluateData("exp",LEVAL5,UNARY_OPERATOR,EXP); functionTable[i++]=new EvaluateData("asin",LEVAL5,UNARY_OPERATOR,ASIN); functionTable[i++]=new EvaluateData("acos",LEVAL5,UNARY_OPERATOR,ACOS); functionTable[i++]=new EvaluateData("atan",LEVAL5,UNARY_OPERATOR,ATAN); functionTable[i++]=new EvaluateData("ln",LEVAL5,UNARY_OPERATOR,LN); functionTable[i++]=new EvaluateData("sqrt",LEVAL5,UNARY_OPERATOR,SQRT); functionTable[i++]=new EvaluateData("^",LEVAL3,BINARY_OPERATOR,POW); functionTable[i++]=new EvaluateData("pi",LEVAL2,NONE,PI); functionTable[i++]=new EvaluateData("log",LEVAL5,UNARY_OPERATOR,LOG); functionTable[i++]=new EvaluateData("x",LEVAL2,NONE,X); functionTable[i++]=new EvaluateData("ans",LEVAL2,NONE,ANS); functionTable[i++]=new EvaluateData("mod",LEVAL6,BINARY_OPERATOR,MOD); functionTable[i++]=new EvaluateData("+",LEVAL7,BINARY_OPERATOR,ADD); functionTable[i++]=new EvaluateData("-",LEVAL7,BINARY_OPERATOR,SUB); functionTable[i++]=new EvaluateData("/",LEVAL6,BINARY_OPERATOR,DIV); functionTable[i++]=new EvaluateData("*",LEVAL6,BINARY_OPERATOR,MUL); hash=new Hashtable(30); for(i=0;i<SIZE;i++) hash.put(functionTable[i].name,functionTable[i]); } public Evaluate(String expression){ this(); setExpression(expression); } public void setExpression(String expression){ this.expression=expression.toLowerCase(); analysis(); } public String getError(){ return errorMessage; } public String getPostfix(){ if(postfix==null) analysis(); return postfix; } public void setX(double x){ this.x=x; } public double getX(){ return x; } public void setDegreeState(boolean isDegree){ this.isDegree=isDegree; } final static int IS_NUMBER=1;// 定義常數,代表數字 final static int IS_LETTER=2;// 定義常數,代表字母 final static int IS_LEFT=4;// 定義常數,代表左括 final static int IS_RIGHT=8;// 定義常數,代表右括 final static int IS_SPACE=16;// 定義常數,代表空白 final static int IS_OTHERS=32;// 定義常數,代表其他 // 將字元分 private int classify(char ch){ if(Character.isLetter(ch)) return IS_LETTER; else if(Character.isDigit(ch) || ch=='.') return IS_NUMBER; else if(Character.isSpace(ch)) return IS_SPACE; else if(ch=='(') return IS_LEFT; else if(ch==')') return IS_RIGHT; else return IS_OTHERS; }//end of classify private void SyntaxError(String str){ errorMessage="Syntax error"+((str==null)?" !":(" : "+str+" !")); throw new NumberFormatException(errorMessage); } private void MethodError(String str){ errorMessage=str+" is not define !"; throw new NoSuchMethodError(errorMessage);// 沒有這函式 } public double getValue(double x){ this.x=x; return this.getValue(); } // 由『後序運算式』求得計算結果 public double getValue(){ int i; double v1=0d,v2; Stack numStack=stack; numStack.removeAllElements();//clear Stack EvaluateData op=null; Double[] value=new Double[2]; for(i=0;i<2;i++) value[i]=new Double(0d); StringTokenizer st=new StringTokenizer(postfix); while(st.hasMoreTokens()){ String token=st.nextToken(); if(classify(token.charAt(0))==IS_NUMBER){ numStack.push(new Double(token)); op=null; } else{ op=(EvaluateData)hash.get(token); }//end of if if(op!=null && op.operator>numStack.size())//new SyntaxError(token); if(op!=null){ for(i=0;i<op.operator;i++) value[i]=(Double)numStack.pop(); switch(op.id){ case SIN : v1=value[0].doubleValue(); if(isDegree) v1=v1*Math.PI/180; v1=Math.sin(v1); break; case COS : v1=value[0].doubleValue(); if(isDegree) v1=v1*Math.PI/180; v1=Math.cos(v1); break; case TAN : v1=value[0].doubleValue(); if(isDegree) v1=v1*Math.PI/180; v1=Math.tan(v1); break; case ASIN : v1=value[0].doubleValue(); v1=Math.asin(v1); if(isDegree) v1=v1*180/Math.PI; break; case ACOS : v1=value[0].doubleValue(); v1=Math.acos(v1); if(isDegree) v1=v1*180/Math.PI; break; case ATAN : v1=value[0].doubleValue(); v1=Math.atan(v1); if(isDegree) v1=v1*180/Math.PI; break; case EXP : v1=value[0].doubleValue(); v1=Math.exp(v1); break; case LN : v1=value[0].doubleValue(); v1=Math.log(v1); break; case SQRT : v1=value[0].doubleValue(); v1=Math.sqrt(v1); break; case POW : v1=value[0].doubleValue(); v2=value[1].doubleValue(); v1=Math.pow(v2,v1); break; case PI : v1=Math.PI; break; case X : v1=x; break; case ADD : v1=value[0].doubleValue(); v2=value[1].doubleValue(); v1=v1+v2; break; case SUB : v1=value[0].doubleValue(); v2=value[1].doubleValue(); v1=v2-v1; break; case MUL : v1=value[0].doubleValue(); v2=value[1].doubleValue(); v1=v2*v1; break; case DIV : v1=value[0].doubleValue(); v2=value[1].doubleValue(); v1=v2/v1; break; case LOG : v1=value[0].doubleValue(); v1=Math.log(v1)/Math.log(10); break; case ANS : v1=lastAnswer; break; case MOD : v1=value[0].doubleValue(); v2=value[1].doubleValue(); v1=Math.IEEEremainder(v2,v1); break; }//end of switch numStack.push(new Double(v1)); }//end if(op.operator<=numStack.size()) }//end of while(st.hasMoreTokens() if(numStack.size()==1) v1=((Double)numStack.pop()).doubleValue(); else SyntaxError(null);// 錯誤 lastAnswer=v1; return v1; }//end of getValue() private void toPostfix(Stack opStack,StringBuffer sbuffer,String op,int priority){ double v1,v2; EvaluateData data; while(!opStack.empty() && priority<((EvaluateData)opStack.peek()).priority){ data=(EvaluateData)opStack.pop(); sbuffer.append(data.name+' '); }//end of while if(op!=null){ data=(EvaluateData)hash.get(op); opStack.push(new EvaluateData(data.name,priority,data.operator,data.id)); } }//end of toPostfix final static int REAL_NUMBER=1; final static int RETURN_NUMBER=2; final static int NOT_NUMBER=4; // 分析中序運算式 ==> 後序運算式 public void analysis(){ int StringIndex,temp,precede=NOT_NUMBER; int thisLeval=0,saveLastPriority=LEVAL8; char ch; Stack opStack=stack; opStack.removeAllElements();//clear stack String token; StringBuffer sbuffer=new StringBuffer(); EvaluateData op,opMul=(EvaluateData)hash.get("*"); for(StringIndex=0;StringIndex<expression.length();){ ch=expression.charAt(StringIndex); switch(classify(ch)){ case IS_SPACE : temp=skipSpace(expression,StringIndex); StringIndex=temp; break; case IS_LETTER : temp=findLetter(expression,StringIndex); token=expression.substring(StringIndex,temp); op=(EvaluateData)hash.get(token); if(op==null) MethodError(token); if(precede!=NOT_NUMBER){// 如果上一個傳回是數字,或是數字則 if(op.operator==UNARY_OPERATOR || op.operator==NONE){ if(precede==REAL_NUMBER && op.operator==NONE) toPostfix(opStack,sbuffer,opMul.name,LEVAL3+thisLeval); else toPostfix(opStack,sbuffer,opMul.name,opMul.priority+thisLeval); } } else if(op.operator==BINARY_OPERATOR)// 假如二元運算前一個不是數字 SyntaxError(op.name); toPostfix(opStack,sbuffer,op.name,op.priority+thisLeval); StringIndex=temp; if(op.operator==NONE){ precede=RETURN_NUMBER; } else{ precede=NOT_NUMBER; } break; case IS_NUMBER : temp=findNumber(expression,StringIndex); sbuffer.append(expression.substring(StringIndex,temp)+' '); StringIndex=temp; precede=REAL_NUMBER; break; case IS_OTHERS : temp=findOperator(expression,StringIndex); token=expression.substring(StringIndex,temp); op=(EvaluateData)hash.get(token); if(op==null) MethodError(token); if(precede==RETURN_NUMBER || precede==REAL_NUMBER){ toPostfix(opStack,sbuffer,op.name,op.priority+thisLeval); } else{ if(op.name.equals("+")){ //不做事 } else if(op.name.equals("-")){ int i=skipSpace(expression,temp); if(classify(expression.charAt(i))==IS_NUMBER){ i=LEVAL3;// ^ 的優先等級 } else i=LEVAL6;//* 的優先等級 sbuffer.append("0 "); //toPostfix(opStack,sbuffer,opMul.name,opMul.priority+thisLeval); toPostfix(opStack,sbuffer,op.name,i+thisLeval); } else SyntaxError(op.name); } StringIndex=temp; precede=NOT_NUMBER; break; case IS_LEFT : if(precede==RETURN_NUMBER || precede==REAL_NUMBER){ toPostfix(opStack,sbuffer,opMul.name,opMul.priority+thisLeval); } if(!opStack.empty()) saveLastPriority=((EvaluateData)opStack.peek()).priority; else saveLastPriority=LEVAL8; thisLeval+=LEVAL1; precede=NOT_NUMBER; StringIndex++; break; case IS_RIGHT : thisLeval-=LEVAL1; if(thisLeval<0) SyntaxError(")"); precede=RETURN_NUMBER; toPostfix(opStack,sbuffer,null,saveLastPriority); StringIndex++; break; } } toPostfix(opStack,sbuffer,null,LEVAL8); if(opStack.size()!=0) SyntaxError(null); else errorMessage="No error !"; postfix=sbuffer.toString(); }//end of analysis() private int findNumber(String str,int start){ int i; boolean error=false; char ch=str.charAt(start); for(i=start;i<str.length();i++){ ch=str.charAt(i); if(!Character.isDigit(ch)) break;//不是數字,則跳出迴圈 }//end of for if(ch=='.') for(i++;i<str.length();i++){ ch=str.charAt(i); if(!Character.isDigit(ch)) break;//不是數字,則跳出迴圈 }//end of for if(ch=='e'){ ch=str.charAt(++i); if(ch!='+' && ch!='-' && !Character.isDigit(ch)){ error=true; } else for(i++;i<str.length();i++){ ch=str.charAt(i); if(!Character.isDigit(ch)) break;//不是數字,則跳出迴圈 }//end of for } if(error) SyntaxError(str.substring(start,i)); return i; }//end of findNumber private int findLetter(String str,int start){ int i; char ch; for(i=start;i<str.length();i++){ ch=str.charAt(i); if(Character.isLetter(ch)) continue; else break; } return i; }//end of findLetter private int skipSpace(String str,int start){ int i; char ch; for(i=start;i<str.length();i++){ ch=str.charAt(i); if(Character.isSpace(ch)) continue; else break; } return i; }//end of skipSpace private int findOperator(String str,int start){ int i=start; char ch=str.charAt(i); if(hash.containsKey(String.valueOf(ch))) return i+1; else//error return i+1; }//end of findOperator }//end of class Evaluate public class WinHw2 extends Applet{ MyPanel2 mainPanel; // 如果是執行 Applet 的話,由此開始執行 public void init(){ mainPanel=new MyPanel2(); setLayout(new BorderLayout(0,0)); add("Center",mainPanel);// 把『我的容器』加到中間 } // 如果是執行 Application 的話,由此開始執行 public static void main(String[] args) { MyFrame2 frame=new MyFrame2("[ Home Work 2 ]"); frame.setLayout(new BorderLayout(0,0)); frame.add("Center",new MyPanel2());// 把『我的容器』加到中間 frame.pack(); frame.show(); } public String getAppletInfo(){ return "Author : Wen-Hung Su/nEmail : b8324057@student.nsysu.edu.tw"; } }//end of class WinHw2